import os  # 导入操作系统接口模块，用于文件和目录操作
import json  # 导入JSON模块，用于数据的序列化和反序列化

class ContactManager:  # 定义联系人管理器类，封装所有联系人相关操作
    def __init__(self, filename="contacts.txt"):  # 类的构造函数，初始化对象属性
        self.filename = filename  # 设置存储联系人数据的文件名，默认为contacts.txt
        self.contacts = []  # 初始化联系人列表为空列表，用于存储所有联系人信息
        self.load_contacts()  # 调用加载联系人方法，从文件中读取已有的联系人数据
    
    def load_contacts(self):  # 定义加载联系人数据的方法
        if os.path.exists(self.filename):  # 检查指定的文件是否存在
            try:  # 使用try-except语句处理可能的文件读取异常
                with open(self.filename, 'r', encoding='utf-8') as f:  # 以只读模式打开文件，使用UTF-8编码防止中文乱码
                    content = f.read().strip()  # 读取文件全部内容并去除首尾空白字符
                    if content:  # 检查文件内容是否非空
                        self.contacts = json.loads(content)  # 将JSON格式的字符串转换为Python列表对象
            except:  # 捕获任何异常（如JSON格式错误、编码错误等）
                self.contacts = []  # 如果出现异常，将联系人列表初始化为空
        else:  # 如果文件不存在
            self.contacts = []  # 将联系人列表初始化为空
    
    def save_contacts(self):  # 定义保存联系人数据到文件的方法
        with open(self.filename, 'w', encoding='utf-8') as f:  # 以写入模式打开文件，使用UTF-8编码支持中文
            json.dump(self.contacts, f, ensure_ascii=False, indent=2)  # 将联系人列表转换为JSON格式写入文件，ensure_ascii=False保证中文正常显示，indent=2使JSON格式化便于阅读
    
    def add_contact(self):  # 定义添加联系人的方法
        print("添加新联系人:")
        name = input("姓名: ").strip()  # 获取用户输入的姓名并去除首尾空白字符
        if not name:  # 检查姓名是否为空
            print("姓名不能为空!")
            return  # 如果姓名为空，结束函数执行
        
        for contact in self.contacts:  # 遍历现有的所有联系人
            if contact['name'] == name:  # 检查是否已存在同名联系人
                print("联系人已存在!")
                return  # 如果存在同名联系人，结束函数执行避免重复添加
        
        phone = input("电话: ").strip()  # 获取用户输入的电话号码并去除首尾空白字符
        email = input("邮箱: ").strip()  # 获取用户输入的邮箱地址并去除首尾空白字符
        address = input("地址: ").strip()  # 获取用户输入的地址信息并去除首尾空白字符
        
        contact = {  # 创建新的联系人字典对象
            'name': name,    # 存储联系人姓名
            'phone': phone,  # 存储联系人电话
            'email': email,  # 存储联系人邮箱
            'address': address  # 存储联系人地址
        }
        
        self.contacts.append(contact)  # 将新联系人添加到联系人列表末尾
        self.save_contacts()  # 调用保存方法将更新后的联系人列表写入文件
        print("联系人添加成功!")
    
    def delete_contact(self):  # 定义删除联系人的方法
        name = input("请输入要删除的联系人姓名: ").strip()  # 获取要删除的联系人姓名并去除首尾空白字符
        if not name:  # 检查输入的姓名是否为空
            print("姓名不能为空!")
            return  # 如果姓名为空，结束函数执行
        
        for i, contact in enumerate(self.contacts):  # 使用enumerate遍历联系人列表，获取索引和联系人对象
            if contact['name'] == name:  # 检查当前联系人的姓名是否匹配要删除的姓名
                del self.contacts[i]  # 根据索引删除指定位置的联系人
                self.save_contacts()  # 保存更新后的联系人列表到文件
                print("联系人删除成功!")
                return  # 删除成功后结束函数执行
        
        print("未找到该联系人!")
    
    def update_contact(self):  # 定义修改联系人信息的方法
        name = input("请输入要修改的联系人姓名: ").strip()  # 获取要修改的联系人姓名并去除首尾空白字符
        if not name:  # 检查输入的姓名是否为空
            print("姓名不能为空!")
            return  # 如果姓名为空，结束函数执行
        
        for contact in self.contacts:  # 遍历联系人列表查找匹配的联系人
            if contact['name'] == name:  # 检查当前联系人的姓名是否匹配
                print(f"当前联系人信息:")
                self.display_contact(contact)  # 调用显示联系人方法展示当前信息
                print("\n请输入新信息 (直接回车保持原值):")
                
                new_phone = input(f"电话 ({contact['phone']}): ").strip()  # 获取新的电话号码，显示当前值作为提示
                new_email = input(f"邮箱 ({contact['email']}): ").strip()  # 获取新的邮箱地址，显示当前值作为提示
                new_address = input(f"地址 ({contact['address']}): ").strip()  # 获取新的地址信息，显示当前值作为提示
                
                if new_phone:  # 检查新电话号码是否非空
                    contact['phone'] = new_phone  # 更新联系人的电话号码
                if new_email:  # 检查新邮箱是否非空
                    contact['email'] = new_email  # 更新联系人的邮箱地址
                if new_address:  # 检查新地址是否非空
                    contact['address'] = new_address  # 更新联系人的地址信息
                
                self.save_contacts()  # 保存更新后的联系人列表到文件
                print("联系人信息更新成功!")
                return  # 更新成功后结束函数执行
        
        print("未找到该联系人!")
    
    def search_contact(self):  # 定义搜索联系人的方法
        keyword = input("请输入搜索关键词 (姓名/电话/邮箱): ").strip()  # 获取搜索关键词并去除首尾空白字符
        if not keyword:  # 检查搜索关键词是否为空
            print("搜索关键词不能为空!")
            return  # 如果关键词为空，结束函数执行
        
        found_contacts = []  # 初始化找到的联系人列表
        for contact in self.contacts:  # 遍历所有联系人
            if (keyword in contact['name'] or   # 检查关键词是否在姓名中
                keyword in contact['phone'] or  # 检查关键词是否在电话中
                keyword in contact['email']):   # 检查关键词是否在邮箱中
                found_contacts.append(contact)  # 如果匹配，将联系人添加到结果列表
        
        if found_contacts:  # 检查是否找到匹配的联系人
            print(f"找到 {len(found_contacts)} 个匹配的联系人:")
            for contact in found_contacts:  # 遍历找到的联系人
                print("-" * 40)
                self.display_contact(contact)  # 调用显示方法展示每个找到的联系人
        else:  # 如果没有找到匹配的联系人
            print("未找到匹配的联系人!")
    
    def display_contact(self, contact):  # 定义显示单个联系人信息的方法，接收联系人字典作为参数
        print(f"姓名: {contact['name']}")    # 格式化输出联系人姓名
        print(f"电话: {contact['phone']}")   # 格式化输出联系人电话
        print(f"邮箱: {contact['email']}")   # 格式化输出联系人邮箱
        print(f"地址: {contact['address']}")  # 格式化输出联系人地址
    
    def display_all_contacts(self):  # 定义显示所有联系人的方法
        if not self.contacts:  # 检查联系人列表是否为空
            print("没有联系人记录!")
            return  # 如果列表为空，结束函数执行
        
        print(f"共有 {len(self.contacts)} 个联系人:")
        for i, contact in enumerate(self.contacts, 1):  # 使用enumerate遍历联系人列表，起始编号为1
            print(f"\n第 {i} 个联系人:")  # 显示联系人序号
            print("-" * 40)
            self.display_contact(contact)  # 调用显示方法展示联系人详细信息
    
    def export_contacts(self):  # 定义导出联系人数据的方法
        if not self.contacts:  # 检查联系人列表是否为空
            print("没有联系人数据可导出!")
            return  # 如果列表为空，结束函数执行
        
        filename = input("请输入导出文件名 (默认为 contacts_export.txt): ").strip()  # 获取导出文件名
        if not filename:  # 检查文件名是否为空
            filename = "contacts_export.txt"  # 如果为空，使用默认文件名
        
        try:  # 使用try-except语句处理可能的文件写入异常
            with open(filename, 'w', encoding='utf-8') as f:  # 以写入模式打开文件，使用UTF-8编码
                f.write("个人联系人管理系统导出数据\n")  # 写入文件头部标题
                f.write("=" * 50 + "\n\n")  # 写入分隔线和空行
                for i, contact in enumerate(self.contacts, 1):  # 遍历联系人列表，起始编号为1
                    f.write(f"联系人 {i}:\n")  # 写入联系人序号
                    f.write(f"姓名: {contact['name']}\n")    # 写入联系人姓名
                    f.write(f"电话: {contact['phone']}\n")   # 写入联系人电话
                    f.write(f"邮箱: {contact['email']}\n")   # 写入联系人邮箱
                    f.write(f"地址: {contact['address']}\n")  # 写入联系人地址
                    f.write("-" * 40 + "\n\n")  # 写入分隔线和空行
            print(f"联系人数据已导出到 {filename}")
        except Exception as e:  # 捕获任何导出过程中的异常
            print(f"导出失败: {e}")  # 显示具体的错误信息
    
    def import_contacts(self):  # 定义导入联系人数据的方法
        filename = input("请输入要导入的文件名: ").strip()  # 获取要导入的文件名
        if not filename or not os.path.exists(filename):  # 检查文件名是否为空或文件是否存在
            print("文件不存在!")
            return  # 如果文件不存在，结束函数执行
        
        try:  # 使用try-except语句处理可能的文件读取异常
            with open(filename, 'r', encoding='utf-8') as f:  # 以只读模式打开文件，使用UTF-8编码
                content = f.read().strip()  # 读取文件全部内容并去除首尾空白字符
                if content:  # 检查文件内容是否非空
                    imported_contacts = json.loads(content)  # 将JSON格式字符串转换为Python对象
                    
                    added_count = 0  # 初始化新增联系人计数器
                    for contact in imported_contacts:  # 遍历导入的联系人列表
                        if contact not in self.contacts:  # 检查联系人是否已存在于当前列表中
                            self.contacts.append(contact)  # 如果不存在，添加到当前联系人列表
                            added_count += 1  # 增加新增联系人计数
                    
                    self.save_contacts()  # 保存更新后的联系人列表到文件
                    print(f"成功导入 {added_count} 个新联系人!")
                else:  # 如果文件内容为空
                    print("文件为空!")
        except Exception as e:  # 捕获任何导入过程中的异常
            print(f"导入失败: {e}")  # 显示具体的错误信息
    
    def run(self):  # 定义运行主程序的方法，实现用户交互界面
        while True:  # 无限循环，直到用户选择退出
            print("\n" + "=" * 50)
            print("个人联系人管理系统")
            print("=" * 50)
            print("1. 添加联系人")
            print("2. 删除联系人")
            print("3. 修改联系人")
            print("4. 查找联系人")
            print("5. 显示所有联系人")
            print("6. 导出联系人")
            print("7. 导入联系人")
            print("0. 退出系统")
            print("-" * 50)
            
            choice = input("请选择操作 (0-7): ").strip()  # 获取用户选择并去除首尾空白字符
            
            if choice == '1':  # 如果用户选择添加联系人
                self.add_contact()  # 调用添加联系人方法
            elif choice == '2':  # 如果用户选择删除联系人
                self.delete_contact()  # 调用删除联系人方法
            elif choice == '3':  # 如果用户选择修改联系人
                self.update_contact()  # 调用修改联系人方法
            elif choice == '4':  # 如果用户选择查找联系人
                self.search_contact()  # 调用查找联系人方法
            elif choice == '5':  # 如果用户选择显示所有联系人
                self.display_all_contacts()  # 调用显示所有联系人方法
            elif choice == '6':  # 如果用户选择导出联系人
                self.export_contacts()  # 调用导出联系人方法
            elif choice == '7':  # 如果用户选择导入联系人
                self.import_contacts()  # 调用导入联系人方法
            elif choice == '0':  # 如果用户选择退出系统
                print("感谢使用个人联系人管理系统!")
                break  # 跳出while循环，结束程序运行
            else:  # 如果用户输入无效选项
                print("无效选择，请重新输入!")

if __name__ == "__main__":  # 检查当前模块是否作为主程序运行（而非被导入）
    manager = ContactManager()  # 创建ContactManager类的实例对象
    manager.run()  # 调用run方法启动联系人管理系统
